#include "Common.h"
#include "BasePassRendering.h"
#include "Material.h"
#include "VertexFactory.h"
#include "Render.h"
#include "Renderable.h"
#include "Material.h"
#include "MaterialInstance.h"
#include "ShaderParameter.h"

const ShaderType BasePassVertexShader::StaticType(
	"BassPassShader.hlsl", 
	"vs_3_0", 
	"VSMain", 
	ShaderType::EST_Vertex, 
	&BasePassVertexShader::ShouldCache,
	&BasePassVertexShader::Create,
	&BasePassVertexShader::Define);

const ShaderType BasePassPixelShader::StaticType(
	"BassPassShader.hlsl", 
	"ps_3_0", 
	"PSMain",
	ShaderType::EST_Pixel, 
	&BasePassPixelShader::ShouldCache,
	&BasePassPixelShader::Create,
	&BasePassPixelShader::Define);

BasePassVertexShader::BasePassVertexShader()
	: mVertexFactoryParam(NULL)
{
}

BasePassVertexShader::~BasePassVertexShader()
{
	SAFE_DELETE(mVertexFactoryParam);
}

bool BasePassVertexShader::Init()
{
	if (!Shader::Init())
		return false;

	mWorldMatrixParam.Bind(this, "WorldMatrix");

	mVertexFactoryParam = mVertexFactoryType->ParamCreator();
	mVertexFactoryParam->Bind(this);
	return true;
}
	
void BasePassVertexShader::SetRenderable(RenderView* view, Renderable* renderable)
{
	Shader::SetRenderable(view, renderable);
	
	mWorldMatrixParam.SetVertexShaderValue(renderable->getWorldMatrix());

	mVertexFactoryParam->SetRenderable(view, renderable);
}

void BasePassPixelShader::Bind(const VertexFactory* vertexFactory, const Material* material)
{
	material->BuildParamRef(this, mMaterialParamRefs);
}
	
void BasePassPixelShader::SetRenderable(RenderView* view, Renderable* renderable)
{
	MaterialInstance* materialInstance = renderable->getMaterial();
	if (materialInstance == NULL)
		return;

	const MaterialParameter& materialParam = materialInstance->getMaterialParam();
	materialParam.Set(mMaterialParamRefs);
}

BasePassDrawingPolicy::BasePassDrawingPolicy(const VertexFactory* vertexFactory, const Material* material)
	: MeshDrawingPolicy(vertexFactory, material)
{ 
	// get the pixel & vertex shader
	mVertexShader = material->getShader<BasePassVertexShader>(vertexFactory->GetType());
	mPixelShader = material->getShader<BasePassPixelShader>(vertexFactory->GetType());
	mPixelShader->Bind(vertexFactory, material);
}

BoundShaderStatePtr BasePassDrawingPolicy::CreateBoundShaderState()
{
	LPDIRECT3DDEVICE9 d3dDevice = Render::Instance().getDevice();
	BoundShaderState* boundShaderState = new BoundShaderState();

	boundShaderState->VertexDeclaration = mVertexFactory->getDeclaration();
	boundShaderState->VertexShader = mVertexShader->getVertexShader();
	boundShaderState->PixelShader = mPixelShader->getPixelShader();

	return BoundShaderStatePtr(boundShaderState);
}

void BasePassDrawingPolicy::DrawShared(BoundShaderStatePtr& boundShaderState)
{
	mVertexFactory->Set();
	boundShaderState->Set();
}

void BasePassDrawingPolicy::DrawRenderable(RenderView* view, Renderable* renderable)
{
	mVertexShader->SetRenderable(view, renderable);

	mPixelShader->SetRenderable(view, renderable);

	MeshDrawingPolicy::DrawRenderable(renderable);
}